/*************************************************************************************
 * Nombre del archivo: CPU.java
 * Universidad del Valle de Guatemala
 * Curso: Sistemas Operativos
 * @author martin
 *          Martín Guzmán 08041
 * Fecha: Febrero de 2010
 * Descripción:
*************************************************************************************/
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
//para parsear el XML
import java.io.*;
import java.util.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;
//******************************************************************************
//estadísticas
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import java.io.File;
//******************************************************************************

public class CPU extends Thread{
    public static String path_xml = "/home/martin/Desktop/Sistemas_operativos/xml/sys.xml";

    public volatile static LinkedList<Interfaz_Cola<Proceso>> lista_colas = new LinkedList<Interfaz_Cola<Proceso>>();

    public volatile static LinkedList<Archivo> Archivos_PID = new LinkedList<Archivo>();//lista de archivos en uso

    public volatile static LinkedList<Proceso> Procesos_por_matar = new LinkedList<Proceso>();
    public volatile static LinkedList<Proceso> Waiting = new LinkedList<Proceso>();
    public volatile static LinkedList<Integer> Waiting_time = new LinkedList<Integer>();
    public volatile static LinkedList<Integer> Waiting_time_cola = new LinkedList<Integer>();
    public volatile static LinkedList<Proceso> Todos_Procesos = new LinkedList<Proceso>();
    public volatile static LinkedList<Proceso> Cola_Procesos_Terminados = new LinkedList<Proceso>();
    public volatile static LinkedList<Proceso> Procesos_a_agregar = new LinkedList<Proceso>();

    public volatile static LinkedList<Semaforo> Semaforos = new LinkedList<Semaforo>();
    
    //public volatile static boolean cambio_proceso = false;

    public volatile static int procesos_sincronos=0;
    public volatile static int contador_ticks=0;

    public static int waiting_time = 5;

    public static Integer Page_tam;

    public static Memoria RAM = new Memoria();
    public static Memoria SWAP = new Memoria();
    public static boolean instruccion_thread = false;

    public volatile static FileSystem fileSystem = new FileSystem();
    
    public CPU(){
        /*
        this.Procesos_por_matar.clear();
        this.Waiting.clear();
        this.Waiting_time.clear();
        this.Waiting_time_cola.clear();
        //this.lista_colas.clear();
        this.Archivos_PID.clear();
        this.Semaforos.clear();
        this.Procesos_a_agregar.clear();
        this.procesos_sincronos=0;
        this.contador_ticks=0;
         */
        Parsear_XML();
    }
    
    /***********************************************
     * Método: run
     * Uso: Método que ejecuta el CPU mientras está
     *      encendido
     *@return void
     ***********************************************/
    public void run() {

        /*
            while(true)
            {
            //actualizar colas y estados puede ser un mismo método
            actualizarColas();
            actualizarEstados();

            process = getProcess();

            //contextSwitch();

            //Puede poner un proceso a terminated o a wait
            exec(process);

            actualizarEstadisticas();
            }
         */
        while(true){
            contador_ticks++;
            Actualizar_Waiting_List();
            //Agregar_procesos();

            //******************************************************************
            int i = get_cola_proceso_a_ejecutar();//obtiene la cola en la que esta el proc
            Proceso proc=null;
            if(i!=-1){
                proc = this.lista_colas.get(i).getFirst();//copia el proceso
                CPU.Mover_Memoria_A_RAM(proc);
            }
            //******************************************************************
            if(proc!=null){
                //**************************************************************
                //ejecutar proceso
                boolean termino = Exec_Proc(proc);
                //System.out.println("Proceso ejecutado: "+proc);
                //**************************************************************
                if(termino){
                    Proceso temp_proc = this.lista_colas.get(proc.cola_en_la_que_esta).poll();
                    Desasignar_Memoria_Proceso(temp_proc);
                    Cola_Procesos_Terminados.add(temp_proc);
                    if(temp_proc.sincrono){
                        this.procesos_sincronos--;
                    }
                }
                //**************************************************************
                if(!this.Procesos_por_matar.isEmpty()){
                    Matar_Procesos();
                }
                //**************************************************************
                proc.restar_Quantum();//resta el quantum del proceso
                //**************************************************************
                if(proc.io_waiting && !termino){
                    //MOVER A LA COLA DE WAITING
                    proc.quantum_over=false;
                    //proc.setQuantum_restante(this.lista_colas.get(proc.cola_en_la_que_esta).getQuantum());
                    try{
                        IO_Context_Switch(proc);
                    }catch(Exception exp){
                        System.out.print("");//("Error en el IO context switch");
                    }


                }
                //**************************************************************

                if(proc.quantum_over && !termino){
                    //proc.io_waiting=false;
                    //HACER CONTEXT SWITCH A LA COLA CORRESPONDIENTE
                    try{
                        Quantum_Context_Switch(proc);
                    }catch(Exception exp){
                        System.out.print("");//("Error en el quantum context switch");
                    }
                }
                
            }
            Actualizar_estadisticas();
        }
    }

    /***********************************************
    * Método: Context_Switch
    * Uso: revisa el cambio de proceso
    *@return void
    ***********************************************/
    public void Quantum_Context_Switch(Proceso proc){
        if(proc!=null){
            //this.print("Quantum context switch");//TODO quitar esto
            //proc.Agregar_Waiting_time();
            //proc.quantum_over=false;
            int cola_fuente = proc.cola_en_la_que_esta;
            proc.setEstado(8);//ponerlo en estado de Queue waiting
            //this.print("Cola en la que esta:"+cola_fuente);
            //this.print("Tamaño cola:"+this.lista_colas.size());
            int cola_destino = this.lista_colas.get(cola_fuente).getQueueOnQuantumEnd();
            //**********************************************************************
            //sacar de una cola y meter en la otra
            if(!this.lista_colas.get(cola_fuente).isEmpty()){
                this.lista_colas.get(cola_destino).add(this.lista_colas.get(cola_fuente).poll());
                //this.Waiting.add(this.lista_colas.get(cola_fuente).poll());
                //this.Waiting_time.add(this.waiting_time);
                //this.Waiting_time_cola.add(cola_destino);
            }
                
        }
    }

     /***********************************************
     * Método: Context_Switch
     * Uso: revisa el cambio de proceso
     *@return void
     ***********************************************/
    public void IO_Context_Switch(Proceso proc){
        //this.print("IO context switch");//TODO quitar esto
        //proc.Agregar_Waiting_time();
        //proc.io_waiting=false;
        int cola_fuente = proc.cola_en_la_que_esta;
        //this.print("Cola fuente: "+cola_fuente);
        //**********************************************************************
        //sacar de una cola y meter en la otra
        this.Waiting.add(this.lista_colas.get(cola_fuente).poll());
        this.Waiting_time.add(this.waiting_time);
        this.Waiting_time_cola.add(this.lista_colas.get(cola_fuente).getQueueOnIOEnd());
        //**********************************************************************
    }

    /***********************************************
     * Método: Actualizar_Waiting_List
     * Uso: Actualiza los valores de tiempo de espera
     *      de cada proceso
     *@return void
     ***********************************************/
    public void Actualizar_Waiting_List(){
        //recorre toda la lista de procesos
        for(int i=0;i<this.Waiting.size();i++){

            //System.out.println("blabla");

            Integer a = CPU.Waiting_time.get(i);
            CPU.Waiting_time.remove(i);
            CPU.Waiting_time.add(i, --a);
            //revisar si ya terminó de esperar para sacarlo...
            if(CPU.Waiting_time.get(i)==0){
                //mete en la respectiva cola
                int cola_destino = this.Waiting_time_cola.get(i);
                Proceso proc = this.Waiting.get(i);
                //this.print("Cola destino: "+cola_destino);
                this.lista_colas.get(cola_destino).add(proc);
                //proc.cola_en_la_que_esta=cola_destino;
                //proc.io_waiting=false;
                //proc.setQuantum_restante(this.lista_colas.get(cola_destino).getQuantum());

                proc.io_waiting=false;
                proc.quantum_over=false;

                this.Waiting.remove(i);
                this.Waiting_time.remove(i);
                this.Waiting_time_cola.remove(i);
                i--;
            }
        }

    }

    /***********************************************
     * Método: Actualizar_estadisticas
     * Uso: Actualiza estadíasticas como el turnarround time
     *      y el waiting time... (implícitamente está el
     *      response time)
     *@return void
     ***********************************************/
    public void Actualizar_estadisticas(){

        //**********************************************************************
        //**********************************************************************
        //actualizar el response time...
        for(int i=0;i<this.lista_colas.size();i++){
            for(int j=0;j<this.lista_colas.get(i).getCola().size();j++){
                this.lista_colas.get(i).get(j).Agregar_Response_time();
            }
        }
        //**********************************************************************
        //this.estado=2;//Ready
        //this.estado=3;//Running
        //this.estado=4;//Waiting
        //this.estado=5;//Terminated
        //this.estado=6;//Killed
        //this.estado=7;//In semaphore

        for(int i=0;i<this.Todos_Procesos.size();i++){
            Proceso proc = this.Todos_Procesos.get(i);
            if(proc.getEstado()==2){
                proc.waiting_time++;
            }
            else if(proc.getEstado()==4 || proc.getEstado()==8){
                proc.Agregar_Waiting_time();
            }
            else if(proc.getEstado()==7){
                proc.semaphore_waiting_time++;
            }
        }
    }

    /***********************************************
     * Método: Asignar_Memoria_Proceso
     * Uso: ejecuta un proceso de la respectiva cola
     * @param numero_proceso contiene el número de
     *        cola del proceso a ejecutar
     *@return void
     ***********************************************/
    public static void Asignar_Memoria_Proceso_Entrante(Proceso proc){
        
        int memoria_necesitada = proc.cant_pages;
        Shell.escribir_mem_log("Asignación de memoria para un proceso entrante: "+proc.process_ID);
        for(int i=0;i<memoria_necesitada;i++){
            if(CPU.RAM.getCantFramesDisponibles()>0){
                int a = CPU.RAM.asignarFrame(proc);
                String cadena = "R "+a;
                proc.Setear_Valor_PageTable(i,cadena);
                Shell.escribir_mem_log("\tAsignación de un frame en RAM");
                Shell.escribir_mem_log("\t\tPágina lógica: "+i+" mapeada a frame: "+a+" de RAM");
            }
            else if(CPU.SWAP.getCantFramesDisponibles()>0){
                int a = CPU.SWAP.asignarFrame(proc);
                String cadena = "S "+a;
                proc.Setear_Valor_PageTable(i,cadena);
                Shell.escribir_mem_log("\tAsignación de un frame en SWAP");
                Shell.escribir_mem_log("\t\tPágina lógica: "+i+" mapeada a frame: "+a+" de SWAP");
            }
            else{
                //no se pudo asignar toda la memoria
                proc.proceso_correcto = false;
                break;
            }
        }
        //proc.Ver_Valor_PageTable();
    }

    /***********************************************
     * Método: Asignar_Memoria_Proceso
     * Uso: ejecuta un proceso de la respectiva cola
     * @param numero_proceso contiene el número de
     *        cola del proceso a ejecutar
     *@return void
     ***********************************************/
    public static void Mover_Memoria_A_RAM(Proceso proc){

        //obtener todas las que tenga en SWAP
        //encontrar a dónde meter
        //sacar de SWAP -> guardar temporal
        //sacar de RAM el primero que no sea este proc -> meter en SWAP
        //guardar en RAM el que estaba en temporal

        //obtener todas las que tenga en SWAP
        HashMap result = new LinkedHashMap();
        HashMap mapa_con_swaps = proc.PageTable;
        Iterator iterator = mapa_con_swaps.keySet().iterator();
        while( iterator. hasNext() ){
            Integer cadena = (Integer) iterator.next();
            String cadena2 = (String) mapa_con_swaps.get(cadena);
            //si es swap lo agrego a result
            if(cadena2.split(" ")[0].compareToIgnoreCase("S")==0){
                result.put(cadena, Integer.parseInt(cadena2.split(" ")[1]));
            }
        }
        //proc.Imprimir("\nLos que tiene el proceso a ejecutar: "+result.toString());

        //encontrar a dónde meter
        Iterator iterator2 = result.keySet().iterator();
        while( iterator2. hasNext() ){

            //System.out.println(CPU.RAM.toString());
            //System.out.println(CPU.SWAP.toString());

            proc.Imprimir("\nLos que tiene el proceso a ejecutar: "+result.toString());
            Integer page_real = (Integer) iterator2.next();
            Integer frame_mapeada = (Integer) result.get(page_real);
            //cambiar con uno de RAM...
            Integer frame_destino = CPU.RAM.getFirstExcept(proc);

            Integer PID_destino = CPU.RAM.procesos_asignados_a_frames[frame_mapeada];
            //******************************************************************
            //obtener proceso del que es destino
            int i = 0;
            Proceso proc2 = null;
            while(true){
                if(PID_destino==CPU.Todos_Procesos.get(i).process_ID){
                    proc2 = CPU.Todos_Procesos.get(i);
                    break;
                }
                i+=1;
            }
            int page_real_destino = -1;
            //******************************************************************
            //proc.Ver_Valor_PageTable();
            //proc2.Ver_Valor_PageTable();
            //obtener page_real_destino
            //******************************************************************
            Iterator iterator3 = proc2.PageTable.keySet().iterator();
            while( iterator3. hasNext() ){
                Integer a = (Integer) iterator3.next();
                String b = (String) proc2.PageTable.get(a);
                if(b.compareToIgnoreCase("R "+frame_destino)==0){
                    page_real_destino = a;
                    break;
                }
            }
            //******************************************************************

            proc.Imprimir("proc: "+proc.process_ID+"\n");
            proc.Imprimir("proc2: "+proc2.process_ID+"\n");
            proc.Imprimir("frame_destino: "+frame_destino+"\n");
            proc.Imprimir("frame_mapeada: "+frame_mapeada+"\n");
            proc.Imprimir("page_real: "+page_real+"\n");
            proc.Imprimir("page_real_destino: "+page_real_destino+"\n");

            Cambiar_en_memoria(frame_mapeada, frame_destino,proc,proc2);
            //intercambiar.. la frame_mapeada <-> frame_destino

            proc.Setear_Valor_PageTable(page_real, "R "+frame_destino);
            proc2.Setear_Valor_PageTable(page_real_destino, "S "+frame_mapeada);

            //System.out.println(CPU.RAM.toString());
            //System.out.println(CPU.SWAP.toString());

            //proc.Ver_Valor_PageTable();
            //proc2.Ver_Valor_PageTable();
        }
        //sacar de SWAP -> guardar temporal
        //sacar de RAM el primero que no sea este proc -> meter en SWAP
        //guardar en RAM el que estaba en temporal


    }

    /***********************************************
     * Método: Cambiar_en_memoria
     * Uso: Agrega todos los procesos que esten en la lista. Estos vienen del shell
     *@return void
     ***********************************************/
    public static void Cambiar_en_memoria(int frame_mapeada, int frame_destino,Proceso proc, Proceso proc2){
        //intercambiar contenidos de los frames de RAM y SWAP
        int[] swap = CPU.SWAP.frames[frame_mapeada].localidad.clone();
        int[] ram = CPU.RAM.frames[frame_destino].localidad.clone();
        CPU.SWAP.procesos_asignados_a_frames[frame_mapeada] = proc2.process_ID;
        CPU.RAM.procesos_asignados_a_frames[frame_destino] = proc.process_ID;

        CPU.SWAP.frames[frame_mapeada].setLocalidades(ram);
        CPU.RAM.frames[frame_destino].setLocalidades(swap);
        Shell.escribir_mem_log("Intercambio de frames entre SWAP y RAM.");
        Shell.escribir_mem_log("\tProcesos involucrados: "+proc2.process_ID+" y "+proc.process_ID);
        Shell.escribir_mem_log("\tFrames intercambiados: "+frame_mapeada+" de SWAP y "+frame_destino+" de RAM");

    }

    /***********************************************
     * Método: Buscar_en_RAM
     * Uso: Agrega todos los procesos que esten en la lista. Estos vienen del shell
     *@return void
     ***********************************************/
    public static int Buscar_en_RAM(int frame, int localidad){
        return CPU.RAM.getLocalidad(frame, localidad);
    }

    /***********************************************
     * Método: Buscar_en_SWAP
     * Uso: Agrega todos los procesos que esten en la lista. Estos vienen del shell
     *@return void
     ***********************************************/
    public static int Buscar_en_SWAP(int frame, int localidad){
        return CPU.SWAP.getLocalidad(frame, localidad);
    }

    /***********************************************
     * Método: Buscar_en_RAM
     * Uso: Agrega todos los procesos que esten en la lista. Estos vienen del shell
     *@return void
     ***********************************************/
    public static boolean Setear_en_RAM(int frame, int localidad, int valor){
        //System.out.println("Setear en RAM: "+frame+" "+localidad+" "+valor);
        Shell.escribir_mem_log("Set al frame: "+frame+", localidad: "+localidad+" de RAM, con el valor: "+valor);
        return CPU.RAM.setLocalidad(frame, localidad, valor);
    }

    /***********************************************
     * Método: Buscar_en_RAM
     * Uso: Agrega todos los procesos que esten en la lista. Estos vienen del shell
     *@return void
     ***********************************************/
    public static boolean Setear_en_SWAP(int frame, int localidad, int valor){
        Shell.escribir_mem_log("Set al frame: "+frame+", localidad: "+localidad+" de SWAP, con el valor: "+valor);
        return CPU.SWAP.setLocalidad(frame, localidad, valor);
    }

    /***********************************************
     * Método: Desasignar_Memoria_Proceso
     * Uso: Borra la memoria que estaba usando un proceso cuando sale..
     * @param numero_proceso contiene el número de
     *        cola del proceso a ejecutar
     *@return void
     ***********************************************/
    public static void Desasignar_Memoria_Proceso(Proceso proc){
        Iterator iterator = proc.PageTable.keySet().iterator();
        Shell.escribir_mem_log("Salida de proceso: "+proc.process_ID+". Se des-asigna la memoria que posee");
        if(iterator. hasNext()==false){
            if(proc.hereda_memoria_de_PID_padre==-1){
                Shell.escribir_mem_log("\tNo tiene memoria asignada");
            }
            else{
                Shell.escribir_mem_log("\tNo tiene memoria asignada por ser proceso hijo");
            }
        }
        while( iterator. hasNext() ){
            Integer a = (Integer) iterator.next();
            String b = (String) proc.PageTable.get(a);

            if(b.split(" ")[0].compareToIgnoreCase("R")==0){
                int c = Integer.parseInt(b.split(" ")[1]);
                CPU.RAM.resetFrame(c);
                Shell.escribir_mem_log("\tFrame des-asignado de la RAM: "+c);
            }
            else if(b.split(" ")[0].compareToIgnoreCase("S")==0){
                int c = Integer.parseInt(b.split(" ")[1]);
                CPU.SWAP.resetFrame(c);
                Shell.escribir_mem_log("\tFrame des-asignado de SWAP: "+c);
            }

        }
    }

    /***********************************************
     * Método: Exec_Proc
     * Uso: ejecuta un proceso de la respectiva cola
     * @param numero_proceso contiene el número de
     *        cola del proceso a ejecutar
     *@return void
     ***********************************************/
    public boolean Exec_Proc(Proceso proc){
        //ejecutar del proceso 1
        //this.print("Ejecutando proceso: "+proc.process_ID);
        return proc.Exec();
    }

     /***********************************************
     * Método: get_proceso_a_ejecutar
     * Uso: Devuelve el proceso a ejecutar
     *@return Proceso con el proceso correspondiente
     ***********************************************/
    public int get_cola_proceso_a_ejecutar() {
        for(int i=0;i<this.lista_colas.size();i++){
            if(!this.lista_colas.get(i).isEmpty()){
                return i;
            }
        }
        return -1;
    }

    /***********************************************
     * Método: contiene_proceso_sincrono
     * Uso: revisa si alguna cola tiene un proceso sincrono
     *@return booleano con la respuesta
     ***********************************************/
    public static boolean contiene_proceso_sincrono(){
        if(CPU.procesos_sincronos>0){
            return true;
        }
        else if(CPU.procesos_sincronos==0){
            return false;
        }
        System.out.println("Clavo al saber si un proceso es síncrono...");
        return false;
        /*
        for(int i=0;i<CPU.lista_colas.size();i++){
            //System.out.println("Cola "+i);
            for(int j=0;j<CPU.lista_colas.get(i).getCola().size();j++){
                //System.out.println("Elemento: "+j);
                if(CPU.lista_colas.get(i).get(j).sincrono){
                    return true;
                }
            }
        }
        return false;
         */
    }

    /***********************************************
     * Método: Matar_Procesos
     * Uso: revisa el cambio de proceso
     *@return void
     ***********************************************/
    public void Matar_Procesos(){

        CPU.Procesos_por_matar.peek().setEstado(6);

        if(CPU.Procesos_por_matar.peek().sincrono){
            this.procesos_sincronos--;
        }

        //System.out.println("si entra hasta acá..");
        //mata el proceso de la cola correspondiente
        for(int i=0;i<this.lista_colas.size();i++){
            if(CPU.lista_colas.get(i).getCola().contains(CPU.Procesos_por_matar.peek())){
                CPU.lista_colas.get(i).remove(CPU.Procesos_por_matar.poll());
            }
        }
    }

    /***********************************************
     * Método: Agregar_Proceso
     * Uso: Agrega un proceso a la cola
     * @param proceso contiene el proceso a agregar
     * @param memoria_pages_requerida contiene la cantidad de pages que requiere el proceso
     *@return void
     ***********************************************/
    public static void Agregar_Proceso(Proceso proceso){
        //System.out.println(proceso.process_ID+" "+proceso.cant_pages);
        int memoria_pages_requerida = proceso.cant_pages;
        //System.out.println("blabla: "+memoria_pages_requerida);
        //validaciones de la cantidad de páginas requeridas
        //no puede ser mayor de la capacidad de la RAM
        if(memoria_pages_requerida > CPU.RAM.getCantFrames()){
            proceso.Imprimir("La memoria requerida ("+memoria_pages_requerida+") por el proceso: "+proceso.process_ID+" excede la que se cuenta en la RAM. Proceso no puede entrar.\n");
            System.out.println("La memoria requerida ("+memoria_pages_requerida+") por el proceso: "+proceso.process_ID+" excede la que se cuenta en la RAM. Proceso no puede entrar.\n");
            proceso.Finalizar_Proceso(5, true,-1);//terminated //registro no encontrado
        }
        else if(memoria_pages_requerida > (CPU.RAM.getCantFramesDisponibles() + CPU.SWAP.getCantFramesDisponibles())){
            proceso.Imprimir("La memoria requerida ("+memoria_pages_requerida+") por el proceso: "+proceso.process_ID+" excede la memoria disponible en el sistema. Proceso no puede entrar.\n");
            System.out.println("La memoria requerida ("+memoria_pages_requerida+") por el proceso: "+proceso.process_ID+" excede la memoria disponible en el sistema. Proceso no puede entrar.\n");
            proceso.Finalizar_Proceso(5, true,-1);//terminated //registro no encontrado
        }
        else{
            //if(CPU.instruccion_thread==false)
                Asignar_Memoria_Proceso_Entrante(proceso);
            //no puede ser mayor de la cantidad de disponibles en la RAM+SWAP
            Todos_Procesos.add(proceso);
            //siempre se agrega a la cola 0
            lista_colas.get(0).add(proceso);
            if(proceso.sincrono){
                CPU.procesos_sincronos++;
            }
            /*
            lista_colas.get(0).getLast_in().setEstado(2);//para cambiar a estado ready
            lista_colas.get(0).getLast_in().cola_en_la_que_esta=0;//para saber dentro del proceso en que cola está
            lista_colas.get(0).getLast_in().quantum_restante = CPU.lista_colas.get(0).getQuantum();//asigna el quantum
             */
        }
        
    }

    /***********************************************
     * Método: Agregar_Procesos
     * Uso: Agrega todos los procesos que esten en la lista. Estos vienen del shell
     *@return void
     ***********************************************/
    public void Agregar_procesos(){
        for(int i=0;i<this.Procesos_a_agregar.size();i++){
            Agregar_Proceso(this.Procesos_a_agregar.get(i));
        }
    }

     /***********************************************
     * Método: Parsear_XML
     * Uso: parsea e inicializa según el contenido del XML
     *@return void
     ***********************************************/
    private void Parsear_XML() {

        try {
            SAXBuilder builder=new SAXBuilder(false);
            //usar el parser Xerces y no queremos
            //que valide el documento
            Document doc=builder.build(path_xml);
            //construyo el arbol en memoria desde el fichero
            // que se lo pasaré por parametro.
            Element raiz=doc.getRootElement();
            //cojo el elemento raiz
            //todos los hijos que tengan como nombre plantilla
            Element cal=raiz.getChild("scheduling");
            Element mem=raiz.getChild("memory");
            int RAM_tam = Integer.parseInt(mem.getAttributeValue("ram"));
            int SWAP_tam = Integer.parseInt(mem.getAttributeValue("swap"));
            int PAGE_tam = Integer.parseInt(mem.getAttributeValue("page"));
            System.out.println(" ***************************************");
            System.out.println("Tamaño de RAM: "+RAM_tam);
            System.out.println("Tamaño de SWAP: "+SWAP_tam);
            System.out.println("Tamaño de PAGE: "+PAGE_tam);
            CPU.Page_tam = PAGE_tam;
            CPU.RAM = new Memoria(RAM_tam,PAGE_tam,"RAM");
            CPU.SWAP = new Memoria(SWAP_tam,PAGE_tam,"SWAP");
            System.out.println("***************************************");
            //CPU.RAM.setLocalidad(0, 12, 123);
            //System.out.println(" ***************************************");
            //System.out.println("RAM: "+RAM.toString());
            //System.out.println("SWAP: "+SWAP.toString());
            //System.out.println(" ***************************************");
            //System.out.println("Valor seteado: "+CPU.RAM.getLocalidad(0, 12));


            int cola_inicial = Integer.parseInt(cal.getAttributeValue("startQueue"));
            System.out.println(" ***************************************");
            System.out.println("Start Queue: "+cola_inicial+"\n");

            try{
                Element path = raiz.getChild("root");
                String root_path = path.getAttributeValue("root_path");
                //System.out.println(root_path);
                Shell.Directorio_Raiz=new File(root_path);
            }catch(Exception exp){
                //System.out.println(Shell.Directorio_Raiz);
            }
            //System.out.println(Shell.Directorio_Raiz.getAbsolutePath());

            List<Element> queue = cal.getChildren("queue");

            //Queue n ***************************************************************************
            for(int i=0;i<queue.size();i++){
                Asignar_datos_cola(queue.get(i),i);
            }
        }catch (Exception e){
            //e.printStackTrace();
            System.out.println("Error parseando XML");
        }
        System.out.println(" ***************************************\n");
    }

    public void Asignar_datos_cola(Element e, int i){

        Interfaz_Cola<Proceso> nueva_cola=null;
        String tipo = e.getAttributeValue("type");

        System.out.println("Queue "+(i+1)+": "+tipo);

        //inicializar según el tipo ********************************************
        if(tipo.compareToIgnoreCase("FCFS")==0){
            nueva_cola = new Cola_FCFS();
        }
        else if(tipo.compareToIgnoreCase("Priority")==0){
            nueva_cola = new Cola_Prioridad();
        }
        else if(tipo.compareToIgnoreCase("SJF")==0){
            nueva_cola = new Cola_SJF();
        }
        //**********************************************************************
        //**********************************************************************
        nueva_cola.setNumero_cola(i);
        nueva_cola.setId(Integer.parseInt(e.getAttributeValue("id")));
        nueva_cola.setName(e.getAttributeValue("name"));
        nueva_cola.setType(tipo);
        if(Integer.parseInt(e.getAttributeValue("preemptive"))==1){
            nueva_cola.setPreemptive(true);
        }
        else{
            nueva_cola.setPreemptive(false);
        }
        nueva_cola.setQuantum(Integer.parseInt(e.getAttributeValue("quantum")));
        nueva_cola.setQueueOnIOEnd(Integer.parseInt(e.getAttributeValue("queueOnIOEnd"))-1);
        nueva_cola.setQueueOnQuantumEnd(Integer.parseInt(e.getAttributeValue("queueOnQuantumEnd"))-1);

        this.lista_colas.add(nueva_cola);
    }

    public void print(String cadena){
        System.out.println(cadena);
    }

}
